package com.lambda.lambda.stream;

import com.lambda.lambda.lambda.Student;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 一、Stream的三个操作步骤：
 * 创建 中间操作 终止操作
 */
public class StreamTest {

    //创建Stream
    @Test
    public void test01(){
        //1、通过Collection系列集合提供的stream（）或parallelStream（）
        ArrayList<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();

        //2、通过Arrays中的静态方法stream（）获取数组流
        Student[] students = new Student[10];
        Stream<Student> stream1 = Arrays.stream(students);

        //3、通过Stream类中的静态发法of（）
        Stream<String> aa = Stream.of("aa", "bb", "cc");

        //4、创建无限流
        //迭代
        Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
        stream4.limit(5).forEach(System.out::println);
        //生成
        Stream.generate(()->Math.random()).limit(5).forEach(System.out::println);
    }


    //中间操作
    /**
     * 筛选与切片
     * filter：接受lambda，从流中排除某些元素
     * limit：截断流，使元素不超过给定数量
     * skip（n）：跳过元素，返回一个跳过前n个元素的流，若流中元素不足n个，则返回一个空流，与limit互补
     * distinct：筛选，通过生成元素的hashcode（）和equals（）去除重复元素
     */
    List<Student> students= Arrays.asList(
            new Student("张三",20,99),
            new Student("李四",10,100),
            new Student("王五",30,100),
            new Student("赵六",30,120)
    );


    //内部迭代：迭代操作由Stream API完成
    @Test
    public void test02(){
        //中间操作：不会执行任何操作
        Stream<Student> studentStream = students.stream().filter(x -> x.getAge() > 10);
        //终止操作：一次性执行全部内容（惰性求值）
        studentStream.forEach(System.out::println);

    }

    //外部迭代：
    @Test
    public void test03(){
        Iterator<Student> iterator = students.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }


    //limit
    @Test
    public void test04(){
    students.stream().filter(e->e.getAge()>5).limit(2).forEach(System.out::println);
    }

    //skip
    @Test
    public void test05(){
        students.stream().filter(e->e.getAge()>5).limit(2).skip(1).forEach(System.out::println);
    }

    //distinct
    @Test
    public void test06(){
        students.stream().filter(e->e.getScore()>99).skip(0).distinct().forEach(System.out::println);
    }

    /**
     * 映射
     * map：接收lambda，将元素转换成其他形式或提取信息，接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新元素
     * flatMap：接受一个函数作为参数，将流中的每个信息转换成另一种流，然后把所有流连成一个流
     */
    @Test
    public void test07(){
        List<String> strings = Arrays.asList("aa", "bb", "cc");
        strings.stream().map(x->x.toUpperCase()).forEach(System.out::println);

        students.stream().map(Student::getName).forEach(System.out::println);
    }


    /**
     * 排序
     * sorted():自然排序
     * sorted(Comparator com):定制排序
     */
    @Test
    public void test08() {
        List<String> strings = Arrays.asList("cc", "bb", "aa");
        strings.stream().sorted().forEach(System.out::println);

        students.stream().sorted((e1, e2) -> {
            if (!e1.getAge().equals(e2.getAge())) {
                return e1.getScore().compareTo(e2.getScore());
            } else {
                return e1.getAge().compareTo(e2.getAge());
            }
        }).forEach(System.out::println);
    }


    /**
     * 终止操作
     *
     * 查找与匹配
     * allMatch：是否匹配所有元素
     * anyMatch：检查是否至少匹配一个元素
     * noneMatch：检查是否没有匹配所有元素
     * findFirst：返回第一个元素
     * findAny：返回任意元素
     * count：返回流中元素总个数
     * max：返回流中最大元素
     * min：返回流中最小元素
     */
    @Test
    public void test09(){
        boolean a = students.stream().allMatch(x -> x.getAge() == 10);
        System.out.println(a);

        boolean b = students.stream().anyMatch(x -> x.getAge() == 10);
        System.out.println(b);

        boolean c = students.stream().noneMatch(x -> x.getAge() == 10);
        System.out.println(c);

        Optional<Student> first = students.stream().findFirst();
        System.out.println(first.get());

        Optional<Student> anyOne = students.stream().findAny();
        System.out.println(anyOne.get());

        long count = students.stream().count();
        System.out.println(count);

        Optional<Student> max = students.stream().max(Comparator.comparingDouble(Student::getAge));
        System.out.println(max.get());

        Optional<Integer> min = students.stream().map(Student::getAge).min(Double::compare);
        System.out.println(min.get());
    }


    /**
     * 归约
     * reduce（T identity，BinaryOperator）/reduce（BinaryOperator）
     * 将流中元素反复结合起来，得到一个值
     */
    @Test
    public void test11(){
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8,9, 10);
        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);

        Optional<Integer> sum1 = students.stream().map(Student::getAge).reduce(Integer::sum);
        System.out.println(sum1.get());
    }

    /**
     * 收集
     * collect
     */
    @Test
    public void test12(){
        List<String> collect = students.stream().map(Student::getName).collect(Collectors.toList());
        System.out.println(collect);

        Set<String> collect1 = students.stream().map(Student::getName).collect(Collectors.toSet());
        collect1.forEach(System.out::println);

        HashSet<String> collect2 = students.stream().map(Student::getName).collect(Collectors.toCollection(HashSet::new));
        System.out.println(collect2);
    }

    @Test
    public void test13(){
        //总数
        Long l = students.stream().collect(Collectors.counting());
        System.out.println(l);

        //平均值
        Double collect = students.stream().collect(Collectors.averagingInt(Student::getAge));
        System.out.println(collect);

        //总和
        Integer collect1 = students.stream().collect(Collectors.summingInt(Student::getAge));
        System.out.println(collect1);

        //最大值
        Optional<Student> collect2 = students.stream().collect(Collectors.maxBy(Comparator.comparingInt(Student::getAge)));
        System.out.println(collect2.get().getAge());

        //最小值
        Optional<Integer> collect3 = students.stream().map(Student::getAge).collect(Collectors.minBy(Integer::compare));
        System.out.println(collect3.get());
    }


    //分组
    @Test
    public void test14(){
        Map<Integer, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getAge));
        System.out.println(collect);

    }

    //多级分组
    @Test
    public void test15(){
        Map<Integer, Map<Integer, List<Student>>> collect = students.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.groupingBy(Student::getScore)));
        System.out.println(collect);

    }

    //分区
    @Test
    public void test16(){
        Map<Boolean, List<Student>> collect = students.stream().collect(Collectors.partitioningBy(x -> x.getScore() >= 100));
        System.out.println(collect);
    }

    @Test
    public void test17(){
        IntSummaryStatistics collect = students.stream().collect(Collectors.summarizingInt(Student::getAge));
        System.out.println(collect.getAverage());
        System.out.println(collect.getMax());
        System.out.println(collect.getCount());
    }

    @Test
    public void test18(){
        String collect = students.stream().map(Student::getName).collect(Collectors.joining(","));
        System.out.println(collect);
    }
}

